<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<!-- Line -->
<script id="TextureVertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    attribute vec2 a_Pin;
    uniform float u_PointSize;
    uniform mat4 u_ModelM4;
    uniform mat4 u_aM4;
    uniform mat4 u_PvM4;
    varying vec2 v_Pin;
    void main(){
        gl_Position = u_PvM4 * u_ModelM4 * a_Position;
        gl_PointSize = u_PointSize;
        v_Pin = a_Pin;
    }
</script>
<script id="TextureFragmentShader" type="x-shader/x-fragment">
    precision mediump float;
    uniform sampler2D u_Sampler;
    varying vec2 v_Pin;
    void main(){
        gl_FragColor = texture2D(u_Sampler, v_Pin);
    }
</script>
<script id="PointVertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform float u_PointSize;
    uniform mat4 u_ModelM4;
    uniform mat4 u_PvM4;
    void main(){
        gl_Position = u_PvM4 * u_ModelM4 * a_Position;
        gl_PointSize = u_PointSize;
    }
</script>
<script id="PointFragmentShader" type="x-shader/x-fragment">
    precision mediump float;
    void main(){
        gl_FragColor = vec4(1,1,1,1);
    }
</script>
<script type="module">
    import { Matrix4, Vector3, Color, PerspectiveCamera, Spherical } from '../js/three.module.js';
    import { initShaders, CreateProgram } from '../js/Utils.js';
    import lib from '../js/ThreeLib.js';
    import CameraController from '../js/CameraController.js'
    import Geo from '../js/Poly/Geo.js'
    import Mat from '../js/Poly/Mat.js'
    import Obj3D from '../js/Poly/Obj3D.js'
    import Scene from '../js/Poly/Scene.js'



    //#region gl
    const canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 4;

    const gl = canvas.getContext("webgl");
    //开始背景遮挡
    gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    //#endregion

    //创建程序对象
    let textureProgram = CreateProgram(gl,
        document.querySelector('#TextureVertexShader').innerText,
        document.querySelector('#TextureFragmentShader').innerText);
    let pointProgram = CreateProgram(gl,
        document.querySelector('#PointVertexShader').innerText,
        document.querySelector('#PointFragmentShader').innerText);

    const scene = new Scene({ gl: gl });
    const perspectiveCamera = new PerspectiveCamera(45, canvas.width / canvas.height, 1, 20);
    const pvM4 = new Matrix4();
    const modelM4 = new Matrix4();
    const pointSize = 15;


    let [imageX, imageY] = [0.3, 1];

    const textureElementArr = [
        0, 1, 2,
        0, 2, 3,
    ];
    const pointElementArr = [
        0, 1,
        1, 2,
        2, 3,
        3, 0,
    ];
    const pinArr = [
        0, 1,
        0, 0,
        1, 0,
        1, 1,
    ];



    let img = new Image();
    img.src = './Image/Image01.jpg';
    imageY = imageX / (img.width / img.height);
    imageY = imageY * (canvas.width / canvas.height);//这个地方应该是显示元素的比值
    const nodeArr = [
        -imageX, imageY,
        -imageX, -imageY,
        imageX, -imageY,
        imageX, imageY,
    ];

    img.onload = function () {

        let textureObj3D = new Obj3D({
            geo: new Geo({
                data: {
                    'a_Position': { size: 2, array: new Float32Array(nodeArr) },
                    'a_Pin': { size: 2, array: new Float32Array(pinArr) },
                },
                element: {
                    array: new Uint8Array(textureElementArr)
                }
            }),
            mat: new Mat({
                program: textureProgram,
                mode: ['TRIANGLES'],
                data: {
                    'u_PvM4': { type: 'uniformMatrix4fv', value: pvM4.elements },
                    'u_ModelM4': { type: 'uniformMatrix4fv', value: modelM4.elements },
                },
                maps: {
                    'u_Sampler': { image: img, WRAP_W: gl.LINEAR, WRAP_H: gl.LINEAR, }
                }
            }),
        });
        let pointObj3D = new Obj3D({
            geo: new Geo({
                data: {
                    'a_Position': { size: 2, array: new Float32Array(nodeArr) },
                },
                element: {
                    array: new Uint8Array(pointElementArr)
                }
            }),
            mat: new Mat({
                program: pointProgram,
                mode: ['POINTS', 'LINES'],
                data: {
                    'u_PvM4': { type: 'uniformMatrix4fv', value: pvM4.elements },
                    'u_ModelM4': { type: 'uniformMatrix4fv', value: modelM4.elements },
                    'u_PointSize': { type: 'uniform1f', value: pointSize },
                },
            }),
        });

        scene.add(pointObj3D);
        scene.add(textureObj3D);
        draw();

    };

    let isDown = false;
    let isScaleDown = false;
    let state = 0;
    //0:不在
    //1:在图形中
    //2:在顶点上
    //3:旋转
    let [moveX, moveY] = [0, 0];
    let nodeIndex = 0;
    let central = new Vector3(0, 0, 0);
    const startAng = 0;//起始弧度


    canvas.addEventListener('mousemove', function (e) {
        const { clientX, clientY } = e;


        let [glX, glY] = CssToGl(clientX, clientY);
        if (glY > nodeArr[3] && glY < nodeArr[1] &&
            glX > nodeArr[0] && glX < nodeArr[4]) {
            //判断是否鼠标是否在图片内
            canvas.style.cursor = "default";
            state = 1;
        } else if (inNode(glX, glY)) {
            state = 2;
            if (nodeIndex % 2 == 0) {
                canvas.style.cursor = "nw-resize";
            } else {
                canvas.style.cursor = "ne-resize";
            }
        } else if (inNode2(glX, glY)) {
            state = 3;
            canvas.style.cursor = "text";
        } else {
            state = 0;
            canvas.style.cursor = "default";
            isDown = false;
        }

        central.x = Math.min(nodeArr[0 * 2], nodeArr[3 * 2]) + (Math.abs(nodeArr[0 * 2]) + Math.abs(nodeArr[3 * 2])) / 2;
        central.y = Math.min(nodeArr[0 * 2 + 1], nodeArr[1 * 2 + 1]) + (Math.abs(nodeArr[0 * 2 + 1]) + Math.abs(nodeArr[1 * 2 + 1])) / 2;

        if (isDown) {
            canvas.style.cursor = "move";
            move(clientX - moveX, (clientY - moveY) * -1);
            moveX = clientX;
            moveY = clientY;
        }
        if (isScaleDown) {
            if (nodeIndex % 2 == 0) {
                canvas.style.cursor = "nw-resize";
            } else {
                canvas.style.cursor = "ne-resize";
            }

            let [oldglX, oldglY] = CssToGl(moveX, moveY);
            scale(central.distanceTo(new Vector3(glX, glY, 0)) - central.distanceTo(new Vector3(oldglX, oldglY, 0)))
            moveX = clientX;
            moveY = clientY;
        }
    })

    canvas.addEventListener('pointerdown', function (e) {
        const { clientX, clientY } = e;
        moveX = clientX;
        moveY = clientY;
        switch (state) {
            case 0:
                return;
            case 1:
                canvas.style.cursor = "move";
                isDown = true;
                break;
            case 2:
                isScaleDown = true;
                break;
        }
    })
    canvas.addEventListener('pointerup', function (e) {
        const { clientX, clientY } = e;

        canvas.style.cursor = "default";
        isDown = false;
        isScaleDown = false;
    })


    //判断是否在顶点附近
    function inNode(glx, gly) {
        var [x, y] = CssToGlOfDiff(pointSize, pointSize);
        for (let i = 0; i < nodeArr.length; i += 2) {
            if (glx > nodeArr[i] - x && glx < nodeArr[i] + x &&
                gly > nodeArr[i + 1] - x && gly < nodeArr[i + 1] + x) {
                nodeIndex = i / 2;
                return true;
            }
        }
        return false;
    }
    function inNode2(glx, gly) {
        var [x, y] = CssToGlOfDiff(pointSize, pointSize);
        x *= 2;
        for (let i = 0; i < nodeArr.length; i += 2) {
            if (glx > nodeArr[i] - x && glx < nodeArr[i] + x &&
                gly > nodeArr[i + 1] - x && gly < nodeArr[i + 1] + x) {
                nodeIndex = i / 2;
                return true;
            }
        }
        return false;
    }


    function draw() {
        scene.setUniform('u_PvM4', { value: pvM4.elements });
        scene.draw();
    }

    function CssToGl(x, y) {
        let hW = canvas.width / 2;
        let hH = canvas.height / 2;
        return [(x - hW) / hW, -1 * (y - hH) / hH];
    }

    function CssToGlOfDiff(x, y) {
        return [x / (canvas.width / 2), y / (canvas.height / 2)]
    }

    function scale(range) {
        range += 1;
        for (let i = 0; i < nodeArr.length; i += 2) {
            var a = new Vector3(nodeArr[i], nodeArr[i + 1], nodeArr[i]).applyMatrix4(new Matrix4().makeScale(range, range, range))
            nodeArr[i] = a.x;
            nodeArr[i + 1] = a.y;
        }
        scene.setAttrib('a_Position', { array: new Float32Array(nodeArr) });
        draw();
        // modelM4.multiply(new Matrix4().makeScale(range, range, range));
        // scene.setUniform('u_ModelM4', { array: modelM4.elements });
        // draw();
    }

    function move(x, y) {
        //直接让每个点进行变化
        let [glx, gly] = CssToGlOfDiff(x, y);
        for (let i = 0; i < nodeArr.length; i += 2) {
            nodeArr[i] += glx;
            nodeArr[i + 1] += gly;
        }
        scene.setAttrib('a_Position', { array: new Float32Array(nodeArr) });
        draw();
    }




</script>

</html>